﻿using DataProcess.Interface;
using HPSocket;
using HPSocket.Tcp;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace DataDrive.TCPIP
{
    public class DataDrive : IDataDrive
    {
        private Config Config { get; set; }

        public event StartedHandler Started;
        public event StopedHandler Stoped;
        public event DataRecivedHandler DataRecived;
        public event ErrorNoticedHandler ErrorNoticed;
        public event WarnNoticedHandler WarnNoticed;
        public event InfoNoticedHandler InfoNoticed;

        private ITcpServer Server { get; set; }

        private ITcpClient Client { get; set; }

        public string Name
        {
            get
            {
                string partial = string.Empty;
                switch (Config.TcpType)
                {
                    case TcpType.Client:
                        partial = $"目标{Config.Address}:{Config.Port}";
                        break;
                    case TcpType.Server:
                        partial = $"本机{Config.Address}:{Config.Port}";
                        break;
                }
                return $"TCP/IP({partial})";
            }
        }

        public string SourceName { get; set; }

        public bool Running
        {
            get
            {
                if (Client != null)
                {
                    return Client.IsConnected;
                }
                else if (Server != null)
                {
                    return Server.HasStarted;
                }
                else
                {
                    return false;
                }
            }
        }

        public DataDrive(Config config)
        {
            Config = config;
            SourceName = $"{config.Address}:{config.Port}";
        }

        public void Start()
        {
            if (Config == null) return;

            if (!Config.Valided())
            {
                WarnNoticed?.Invoke($"数据驱动配置不全,无法启用驱动.详情如下:{Config.Message}");
                return;
            }
            string msgPre = $"服务器{Config.Address}:{Config.Port}";

            bool started = false;
            switch (Config.TcpType)
            {
                case TcpType.Client:
                    Client = new TcpClient()
                    {
                        Address = Config.Address,
                        Port = (ushort)Config.Port,
                    };
                    Client.OnClose += Client_OnClose;
                    Client.OnConnect += Client_OnConnect;
                    Client.OnReceive += Client_OnReceive;
                    if (Client.Connect(Config.Address, (ushort)Config.Port))
                    {
                        InfoNoticed?.Invoke($"{msgPre}连接成功");
                        started = true;
                    }
                    else
                    {
                        ErrorNoticed?.Invoke($"{msgPre}连接失败");
                    }
                    break;
                case TcpType.Server:
                    Server = new TcpServer()
                    {
                        Address = Config.Address,
                        Port = (ushort)Config.Port,
                    };
                    Server.OnAccept += Server_OnAccept;
                    Server.OnClose += Server_OnClose;
                    Server.OnReceive += Server_OnReceive;
                    int retry = 0;

                    ServerStart:
                    {
                        started = Server.Start();
                    }

                    Thread.Sleep(500);

                    if (!started)
                    {
                        if (retry <= 3)
                        {
                            retry++;
                            ErrorNoticed?.Invoke($"{msgPre}启动失败,尝试第{retry}次重试");
                            goto ServerStart;
                        }
                        else
                        {
                            ErrorNoticed?.Invoke($"启动{msgPre}三次重试失败，请尝试人工启用");
                        }
                    }
                    else
                    {
                        InfoNoticed?.Invoke($"{msgPre}启动成功,等待客户端接入");
                        started = true;
                    }
                    break;
                default:
                    break;
            }
            if (started) Started?.Invoke();
        }


        public void Stop()
        {
            if (Server != null) Server.Stop();
            if (Client != null) Client.Stop();
            Stoped?.Invoke();
        }

        public void Dispose()
        {
            if (Server != null)
            {
                Server.Stop();
                Server.Dispose();
            }

            if (Client != null)
            {
                Client.Stop();
                Client.Dispose();
            }
        }

        #region TcpClient

        private HandleResult Client_OnReceive(IClient sender, byte[] data)
        {
            DataRecived?.Invoke(Encoding.UTF8.GetString(data));
            return HandleResult.Ok;
        }

        private HandleResult Client_OnConnect(IClient sender)
        {
            InfoNoticed?.Invoke($"服务器{sender.Address}:{sender.Port}已连接");
            return HandleResult.Ok;
        }

        private HandleResult Client_OnClose(IClient sender, SocketOperation socketOperation, int errorCode)
        {
            if (errorCode == 0)
            {
                InfoNoticed?.Invoke($"已断开与服务器{sender.Address}:{sender.Port}的连接");
            }
            else
            {
                ErrorNoticed?.Invoke($"已断开与服务器{sender.Address}:{sender.Port}的连接,错误码为{errorCode}");
            }
            return HandleResult.Ok;
        }

        #endregion

        #region TcpServer
        private HandleResult Server_OnReceive(IServer sender, IntPtr connId, byte[] data)
        {
            DataRecived?.Invoke(Encoding.UTF8.GetString(data));
            return HandleResult.Ok;
        }

        private HandleResult Server_OnClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            if (errorCode != 0)
            {
                ErrorNoticed?.Invoke($"客户端已断开连接,错误码为{errorCode}");
            }
            sender.Disconnect(connId);
            return HandleResult.Ok;
        }

        private HandleResult Server_OnAccept(IServer sender, IntPtr connId, IntPtr client)
        {
            InfoNoticed?.Invoke($"客户端已接入");
            return HandleResult.Ok;
        }
        #endregion
    }

    public class Config : IDataDriveConfig
    {
        [Display(Name = "Tcp类型")]
        [Required(ErrorMessage = "Tcp类型必须选择")]
        public TcpType TcpType { get; set; }

        [Display(Name = "地址")]
        public string Address { get; set; }

        [Display(Name = "端口号")]
        public int Port { get; set; }

        [Display(AutoGenerateField = false)]
        public string Message { get; set; }

        public bool Valided()
        {
            if (string.IsNullOrEmpty(Address))
            {
                Message = "[地址]不能为空";
                return false;
            }
            else
            {
                if (!Regex.IsMatch(Address, @"((([1-9]?|1\d)\d|2([0-4]\d|5[0-5]))\.){3}(([1-9]?|1\d)\d|2([0-4]\d|5[0-5]))"))
                {
                    Message = "[地址]格式不正确，正确的写法如：192.168.1.1";
                    return false;
                }
            }

            if (Port < 0 || Port > 65535)
            {
                Message = "[端口号]必须要再0-65535之间";
                return false;
            }

            return true;
        }
    }

    public enum TcpType
    {
        [Description("客户端")]
        Client,
        [Description("服务端")]
        Server
    }

}
